// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
// import com.alibaba.druid.sql.visitor.SQLEvalVisitor;

// import java.util.Calendar;
// import java.util.Date;
// import java.util.List;

// import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_ERROR;
// import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_VALUE;

#include "DateAdd.h"
#include "../SQLEvalVisitor.h"
#include "../../../utils/StringUtils.h"

DateAdd *DateAdd::instance()
{
  static DateAdd x;
  return &x;
}
Object_ptr DateAdd::eval(SQLEvalVisitor *visitor, SQLMethodInvokeExpr *x)
{
  SQLExpr_list_ptr arguments = x->getArguments();
  if (arguments->size() != 3)
  {
    return SQLEvalVisitor::EVAL_ERROR;
  }

  for (SQLExpr_ptr arg : *arguments)
  {
    arg->accept(SQLEvalVisitor_ptr(visitor));
  }

  auto it_arguments = arguments->begin();
  std::advance(it_arguments, 0);
  auto v0_ = *it_arguments;
  std::advance(it_arguments, 1);
  auto v1_ = *it_arguments;
  std::advance(it_arguments, 2);
  auto v2_ = *it_arguments;

  auto v0__ = v0_->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
  Object_ptr v0 = nullptr;
  if (v0__ != v0_->getAttributes()->end())
  {
    v0 = v0__->second;
  }
  auto v1__ = v1_->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
  Object_ptr v1 = nullptr;
  if (v1__ != v1_->getAttributes()->end())
  {
    v1 = v1__->second;
  }
  auto v2__ = v2_->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
  Object_ptr v2 = nullptr;
  if (v2__ != v2_->getAttributes()->end())
  {
    v2 = v2__->second;
  }

  if (v0->getType() == Object::ParamType::LONG && v1->getType() == Object::ParamType::INT && v2->getType() == Object::ParamType::STRING)
  {
    time_t date = (time_t)v0->getLong();
    int delta = v1->getInt();

    if (StringUtils::iequals("day", v2->getString()))
    {
      std::string myFormat = "%d";
      struct tm *myt = localtime(&date);
      char myStr[255] = "\0";
      strftime(myStr, sizeof(myStr), myFormat.c_str(), myt);
      return Object_ptr(new Object(myStr));
      // Calendar calendar = Calendar.getInstance();
      // calendar.setTime(date);
      // calendar.add(Calendar.DAY_OF_MONTH, delta);

      // return calendar.getTime();
    }
  }

  SQLExpr_ptr arg = v0_;
  arg->accept(SQLEvalVisitor_ptr(visitor));
  Object_ptr itemValue = nullptr;
  auto tmp = arg->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
  if (tmp != arg->getAttributes()->end())
  {
    itemValue = tmp->second;
  }
  if (itemValue == nullptr)
  {
    return nullptr;
  }

  return nullptr;
}
